﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
using VietPay.KooBoo.Data.Infrastructure;
using VietPay.KooBoo.Business.Models;
using VietPay.KooBoo.Business.Interfaces;
using VietPay.KooBoo.Data.Interfaces;
using VietPay.KooBoo.Data;
using VietPay.KooBoo.Data.EntityModels;
using System.Transactions;
using VietPay.KooBoo.Common;
using Newtonsoft.Json;

namespace VietPay.KooBoo.Business
{
    public class BatchService : ServiceBase<IBatchModel>, IBatchService
    {
        public BatchService()
            : this(new BatchRepository())
        {
        }

        private IBatchRepository _repository;
        
        public BatchService(IBatchRepository newsRepository)
        {
            _repository = newsRepository ?? new BatchRepository();          
        }

        protected override Type LogPrefix
        {
            get { return this.GetType(); }
        }

        public BatchListViewModel GetBatchList(int PageSize, int CurrentPage)
        {
            try
            {
                if ((CurrentPage == 0) || (PageSize == 0))
                    return null;

                IQueryable<Batch> query = _repository.GetQueryable();
                BatchListViewModel model = new BatchListViewModel();
                model.TotalItemCount = query.Count();
                if (model.TotalItemCount == 0)
                    return null;
                model.TotalPageCount = (int)Math.Ceiling((double)model.TotalItemCount / (double)PageSize);
                if (model.TotalPageCount != 1)
                    query = query.OrderBy(x => x.BatchID).Skip((CurrentPage - 1) * PageSize).Take(PageSize);

                model.ThisPageItemCount = query.Count();

                model.BatchList= new List<BatchViewModel>();
                AutoMapper.Mapper.CreateMap<Batch, BatchViewModel>()
                    .ForMember(dest => dest.BatchID, opt => opt.MapFrom(src => src.BatchID))
                    .ForMember(dest => dest.BatchCode, opt => opt.MapFrom(src => src.BathCode))
                    .ForMember(dest => dest.CreatedDate, opt => opt.MapFrom(src => src.CreatedDate))
                    .ForMember(dest => dest.DistributorID, opt => opt.MapFrom(src => src.DistributorID))
                    .ForMember(dest => dest.ParentDistributorID, opt => opt.MapFrom(src => src.ParentDistributorID))
                    .ForMember(dest => dest.Description, opt => opt.MapFrom(src => src.Description));
                model.BatchList = AutoMapper.Mapper.Map(query.ToList(), model.BatchList);

                return model;
            }
            catch (System.Exception e)
            {
                this.LogError("Error getting the Batch list", e);
                return null;
            }
        }

        public BatchListViewModel GetBatchSearch(int? parentDistibutorID, string distributorCode, BatchSearchViewModel bathViewModel, int PageSize, int CurrentPage)
        {
            try
            {
                if ((CurrentPage == 0) || (PageSize == 0))
                    return null;

                var vms = new VMS2_DistributorEntities();

                var result = (from b in vms.Batches
                              join c in vms.Categories on b.CategoryID equals c.CategoryID
                              join bd in vms.BatchDetails on b.BatchID equals bd.BatchID into g
                              select new BatchSearchViewModel
                              {
                                  ParentDistributorID = b.ParentDistributorID,
                                  BatchID = b.BatchID,
                                  CategoryID= c.CategoryID,
                                  CategoryName = c.CategoryName,
                                  BatchCode = b.BathCode,
                                  CreatedDate = b.CreatedDate,
                                  Quantity = g.Sum(p => p.Quantity)
                              }).OrderBy(p => p.CategoryName);

                List<BatchSearchViewModel> lst = result.ToList<BatchSearchViewModel>();

                if (parentDistibutorID.HasValue)
                    lst = lst.Where(p => p.ParentDistributorID == parentDistibutorID).ToList();

                if (!String.IsNullOrEmpty(bathViewModel.BatchCode))
                    lst = lst.Where(p => p.BatchCode.Contains(bathViewModel.BatchCode)).ToList();

                if (!String.IsNullOrEmpty(bathViewModel.CategoryName))
                    lst = lst.Where(p => p.BatchCode.Contains(bathViewModel.CategoryName)).ToList();

                if (bathViewModel.FromCreatedDate.HasValue)
                    lst = lst.Where(p => p.CreatedDate >= bathViewModel.FromCreatedDate).ToList();

                if (bathViewModel.ToCreatedDate.HasValue)
                    lst = lst.Where(p => p.CreatedDate <= bathViewModel.ToCreatedDate).ToList();

                if (bathViewModel.StatusValue.HasValue)
                    lst = lst.Where(p => p.StatusValue == bathViewModel.StatusValue).ToList();
                if (bathViewModel.CategoryID.HasValue)
                    lst = lst.Where(p => p.CategoryID == bathViewModel.CategoryID).ToList();

                BatchListViewModel model = new BatchListViewModel();
                model.TotalItemCount = lst.Count();
                if (model.TotalItemCount == 0)
                    return null;
                model.TotalPageCount = (int)Math.Ceiling((double)model.TotalItemCount / (double)PageSize);
                if (model.TotalPageCount != 1)
                    lst = lst.OrderBy(x => x.BatchID).Skip((CurrentPage - 1) * PageSize).Take(PageSize).ToList();

                model.BatchSearchList = lst;
                return model;
            }
            catch (System.Exception e)
            {
                this.LogError("Error getting the Batch list", e);
                return null;
            }
        }

        public void BatchCreate(Batch batch, List<BatchDetail> lstBatchDetail)
        {
            System.Data.Common.DbTransaction dbTran = null;
            using (var vmsEntity = new VMS2_DistributorEntities())
            {
                try
                {
                    #region //Init
                    vmsEntity.Connection.Open();
                    dbTran = vmsEntity.Connection.BeginTransaction();
                    #endregion

                    #region //Check
                    //1. Kiểm tra thông tin BatchDetail
                    //--Check null
                    if (lstBatchDetail==null || lstBatchDetail.Count==0)
                    {
                        this.LogError("Không có chi tiết đặt hàng.");
                        return;
                    }
                    //--Check Duplicate
                    
                    #endregion

                    #region //1. Create batch
                    vmsEntity.Batches.AddObject(batch);
                    vmsEntity.SaveChanges();
                    #endregion

                    //2. BatchDetail                    
                    foreach (var item in lstBatchDetail)
                    {
                        #region //Check Product StockBalance
                        //2. tồn kho theo Distributor & product
                        StockBalance productBalance = vmsEntity.StockBalances.FirstOrDefault(p => p.DistributorID == batch.ParentDistributorID
                                                 && p.ProductID == item.ProductID);
                        if (productBalance==null || productBalance.Quantity<item.Quantity)
                        {
                            this.LogInfo(Constant.PruductNotEnough);
                            return;
                        }
                        else
                        {
                            //tru so luong xuat
                            productBalance.Quantity = productBalance.Quantity - item.Quantity;
                            vmsEntity.SaveChanges();
                        }
                        #endregion

                        #region // add BatchDetail
                        item.BatchID = batch.BatchID;
                        vmsEntity.BatchDetails.AddObject(item);
                        vmsEntity.SaveChanges();
                        #endregion

                        #region //2.1 Update oldBalanceDetail Balance
                        ////Get:
                        //BatchDetail btDetail = vmsEntity.BatchDetails.Where(p => p.ID == 1 && p.ProductID == item.ProductID).FirstOrDefault();
                        //btDetail.QuantityBalance = btDetail.QuantityBalance - item.Quantity;
                        ////update:
                        //vmsEntity.BatchDetails.Attach(btDetail);
                        //vmsEntity.SaveChanges();
                        #endregion

                        #region //2.2 Update Stockbalance:
                        StockBalance balance = vmsEntity.StockBalances.Where(p => p.DistributorID == batch.DistributorID && p.ProductID == item.ProductID).FirstOrDefault();
                        if (balance == null)
                        {
                            balance = new StockBalance();
                            balance.ProductID = item.ProductID;
                            balance.Quantity = item.Quantity;
                            balance.DistributorID = batch.DistributorID;

                            vmsEntity.StockBalances.AddObject(balance);
                            vmsEntity.SaveChanges();
                        }
                        else
                        {
                            //update
                            balance.Quantity = balance.Quantity + item.Quantity;
                            vmsEntity.SaveChanges();
                        }
                        //BalanceHistory
                        StockBalanceHistory history = new StockBalanceHistory();
                        history.BatchDetailID = item.ID;
                        history.BalanceID = balance.BalanceID;
                        history.CreatedDate = DateTime.Now;
                        vmsEntity.StockBalanceHistories.AddObject(history);
                        vmsEntity.SaveChanges();
                        #endregion

                        #region //2.3 Goods
                        //Lấy danh sách hàng của Parent Batch
                        int iQty = 0;
                        List<Good> lstGood = vmsEntity.Goods.Where(p => p.ProductID == item.ProductID).ToList();
                        //List<Good> lstGood = vmsEntity.Goods.Where(p => p.ProductID == item.ProductID
                        //                    && JsonConvert.DeserializeObject<List<BatchGoodsTree>>(p.Tree).Last().DistributorID==batch.ParentDistributorID)
                        //                    .OrderBy(p=>p.GoodsID)
                        //                    .Take(item.Quantity)
                        //                    .ToList();

                        //var result = (from p in vmsEntity.Goods
                        //             where p.ProductID == item.ProductID
                        //             && JsonConvert.DeserializeObject<List<BatchGoodsTree>>(p.Tree).Last().DistributorID == batch.ParentDistributorID
                        //             select p).Take(item.Quantity);

                        //List<Good> lstGood = result.ToList();

                        foreach (var igood in lstGood)
                        {
                            List<BatchGoodsTree> deserializedGoodTree = JsonConvert.DeserializeObject<List<BatchGoodsTree>>(igood.Tree);
                            BatchGoodsTree batchGoodTree= deserializedGoodTree.Last();
                            if (batchGoodTree != null && batchGoodTree.DistributorID==batch.ParentDistributorID)
                            {
                                BatchGoodsTree batchGoodTreeNew = new BatchGoodsTree();
                                batchGoodTreeNew.DistributorID = batch.DistributorID;
                                batchGoodTreeNew.BatchDetailID = item.ID;//batchDetailID
                                deserializedGoodTree.Add(batchGoodTreeNew);//Phân phối cho điểm bán mới.
                                igood.Tree = JsonConvert.SerializeObject(deserializedGoodTree);
                                //update Goods
                                vmsEntity.SaveChanges();
                                iQty++;
                            }
                            if (iQty == item.Quantity) break;
                        }
                        #endregion
                    }

                    #region //Return
                    dbTran.Commit();
                    #endregion
                }
                catch (Exception ex)
                {
                    dbTran.Rollback();
                    this.LogError("Error create batch: ", ex);
                }
                finally
                {
                    //finally
                    vmsEntity.Connection.Close();
                }
            }
        }

        public void BatchCreateGoods(Batch batch, List<BatchDetail> lstBatchDetail, List<Good> lstGood)
        {
            System.Data.Common.DbTransaction dbTran = null;
            using (var vmsEntity = new VMS2_DistributorEntities())
            {
                try
                {
                    #region //Init
                    vmsEntity.Connection.Open();
                    dbTran = vmsEntity.Connection.BeginTransaction();
                    #endregion

                    #region //Check
                    //1. Kiểm tra thông tin BatchDetail
                    //--Check null
                    if (lstBatchDetail == null || lstBatchDetail.Count == 0)
                    {
                        this.LogError("Không có chi tiết đặt hàng.");
                        return;
                    }
                    if (lstGood== null || lstGood.Count == 0)
                    {
                        this.LogError("Không có chi tiết hàng hóa.");
                        return;
                    }
                    //--Check Duplicate

                    #endregion

                    #region //1. Create batch
                    vmsEntity.Batches.AddObject(batch);
                    vmsEntity.SaveChanges();
                    #endregion

                    //2. BatchDetail                    
                    foreach (var item in lstBatchDetail)
                    {
                        #region //Check Product StockBalance
                        //2. tồn kho theo Distributor & product
                        StockBalance productBalance = vmsEntity.StockBalances.FirstOrDefault(p => p.DistributorID == batch.ParentDistributorID
                                                 && p.ProductID == item.ProductID);
                        if (productBalance == null || productBalance.Quantity < item.Quantity)
                        {
                            this.LogInfo(Constant.PruductNotEnough);
                            return;
                        }
                        else
                        {
                            //tru so luong xuat
                            productBalance.Quantity = productBalance.Quantity - item.Quantity;
                            vmsEntity.SaveChanges();
                        }
                        #endregion

                        #region // add BatchDetail
                        item.BatchID = batch.BatchID;
                        vmsEntity.BatchDetails.AddObject(item);
                        vmsEntity.SaveChanges();
                        #endregion

                        #region //2.1 Update oldBalanceDetail Balance
                        ////Get:
                        //BatchDetail btDetail = vmsEntity.BatchDetails.Where(p => p.ID == 1 && p.ProductID == item.ProductID).FirstOrDefault();
                        //btDetail.QuantityBalance = btDetail.QuantityBalance - item.Quantity;
                        ////update:
                        //vmsEntity.BatchDetails.Attach(btDetail);
                        //vmsEntity.SaveChanges();
                        #endregion

                        #region //2.2 Update Stockbalance:
                        StockBalance balance = vmsEntity.StockBalances.Where(p => p.DistributorID == batch.DistributorID && p.ProductID == item.ProductID).FirstOrDefault();
                        if (balance == null)
                        {
                            balance = new StockBalance();
                            balance.ProductID = item.ProductID;
                            balance.Quantity = item.Quantity;
                            balance.DistributorID = batch.DistributorID;

                            vmsEntity.StockBalances.AddObject(balance);
                            vmsEntity.SaveChanges();
                        }
                        else
                        {
                            //update
                            balance.Quantity = balance.Quantity + item.Quantity;
                            vmsEntity.SaveChanges();
                        }
                        //BalanceHistory
                        StockBalanceHistory history = new StockBalanceHistory();
                        history.BatchDetailID = item.ID;
                        history.BalanceID = balance.BalanceID;
                        history.CreatedDate = DateTime.Now;
                        vmsEntity.StockBalanceHistories.AddObject(history);
                        vmsEntity.SaveChanges();
                        #endregion

                        #region //2.3 Goods
                        foreach (var igood in lstGood)
                        {
                            List<BatchGoodsTree> deserializedGoodTree = JsonConvert.DeserializeObject<List<BatchGoodsTree>>(igood.Tree);
                            BatchGoodsTree batchGoodTree = deserializedGoodTree.Last();
                            if (batchGoodTree != null && batchGoodTree.DistributorID == batch.ParentDistributorID)
                            {
                                BatchGoodsTree batchGoodTreeNew = new BatchGoodsTree();
                                batchGoodTreeNew.DistributorID = batch.DistributorID;
                                batchGoodTreeNew.BatchDetailID = item.ID;//batchDetailID
                                deserializedGoodTree.Add(batchGoodTreeNew);//Phân phối cho điểm bán mới.
                                igood.Tree = JsonConvert.SerializeObject(deserializedGoodTree);
                                //update Goods
                                vmsEntity.SaveChanges();
                            }
                        }
                        #endregion
                    }

                    #region //Return
                    dbTran.Commit();
                    #endregion
                }
                catch (Exception ex)
                {
                    dbTran.Rollback();
                    this.LogError("Error create batch: ", ex);
                }
                finally
                {
                    //finally
                    vmsEntity.Connection.Close();
                }
            }
        }

        public void BatchVMSCreateGoods(Batch batch, List<BatchDetail> lstBatchDetail, List<Good> lstGood)
        {
            System.Data.Common.DbTransaction dbTran = null;
            using (var vmsEntity = new VMS2_DistributorEntities())
            {
                try
                {
                    #region //Init
                    vmsEntity.Connection.Open();
                    dbTran = vmsEntity.Connection.BeginTransaction();
                    #endregion

                    #region //Check
                    //1. Kiểm tra thông tin BatchDetail
                    //--Check null
                    if (lstBatchDetail == null || lstBatchDetail.Count == 0)
                    {
                        this.LogError("Không có chi tiết đặt hàng.");
                        return;
                    }
                    if (lstGood == null || lstGood.Count == 0)
                    {
                        this.LogError("Không có chi tiết hàng hóa.");
                        return;
                    }
                    //--Check Duplicate

                    #endregion

                    #region //1. Create batch
                    vmsEntity.Batches.AddObject(batch);
                    vmsEntity.SaveChanges();
                    #endregion

                    //2. BatchDetail                    
                    foreach (var item in lstBatchDetail)
                    {
                        #region //Check Product StockBalance
                        
                        #endregion

                        #region // add BatchDetail
                        item.BatchID = batch.BatchID;
                        vmsEntity.BatchDetails.AddObject(item);
                        vmsEntity.SaveChanges();
                        #endregion

                        #region //2.1 Update oldBalanceDetail Balance
                        ////Get:
                        //BatchDetail btDetail = vmsEntity.BatchDetails.Where(p => p.ID == 1 && p.ProductID == item.ProductID).FirstOrDefault();
                        //btDetail.QuantityBalance = btDetail.QuantityBalance - item.Quantity;
                        ////update:
                        //vmsEntity.BatchDetails.Attach(btDetail);
                        //vmsEntity.SaveChanges();
                        #endregion

                        #region //2.2 Update Stockbalance:
                        StockBalance balance = vmsEntity.StockBalances.Where(p => p.DistributorID == batch.DistributorID && p.ProductID == item.ProductID).FirstOrDefault();
                        if (balance == null)
                        {
                            balance = new StockBalance();
                            balance.ProductID = item.ProductID;
                            balance.Quantity = item.Quantity;
                            balance.DistributorID = batch.DistributorID;

                            vmsEntity.StockBalances.AddObject(balance);
                            vmsEntity.SaveChanges();
                        }
                        else
                        {
                            //update
                            balance.Quantity = balance.Quantity + item.Quantity;
                            vmsEntity.SaveChanges();
                        }
                        //BalanceHistory
                        StockBalanceHistory history = new StockBalanceHistory();
                        history.BatchDetailID = item.ID;
                        history.BalanceID = balance.BalanceID;
                        history.CreatedDate = DateTime.Now;
                        vmsEntity.StockBalanceHistories.AddObject(history);
                        vmsEntity.SaveChanges();
                        #endregion

                        #region //2.3 Create Goods
                        foreach (var igood in lstGood)
                        {
                            List<BatchGoodsTree> deserializedGoodTree = new List<BatchGoodsTree>();
                            
                            BatchGoodsTree batchGoodTreeNew = new BatchGoodsTree();
                            batchGoodTreeNew.DistributorID = batch.DistributorID;
                            batchGoodTreeNew.BatchDetailID = item.ID;//batchDetailID
                            deserializedGoodTree.Add(batchGoodTreeNew);//add VMS tree
                            igood.Tree = JsonConvert.SerializeObject(deserializedGoodTree);
                            //update Goods
                            vmsEntity.Goods.AddObject(igood);
                            vmsEntity.SaveChanges();
                        }
                        #endregion
                    }

                    #region //Return
                    dbTran.Commit();
                    #endregion
                }
                catch (Exception ex)
                {
                    dbTran.Rollback();
                    this.LogError("Error create batch: ", ex);
                }
                finally
                {
                    //finally
                    vmsEntity.Connection.Close();
                }
            }
        }

        public BatchViewModel GetSingle(Expression<Func<BatchViewModel, bool>> whereCondition)
        {
            throw new NotImplementedException();
        }

        public void Add(BatchViewModel vModel)
        {
            Batch entity=new Batch();

            entity.BathCode = vModel.BatchCode;
            entity.CreatedDate= vModel.CreatedDate;
            entity.Description= vModel.Description;
            entity.DistributorID= vModel.DistributorID;
            entity.ParentDistributorID= vModel.ParentDistributorID;
            _repository.Add(entity);
        }

        public void Delete(BatchViewModel vModel)
        {
            Batch news = _repository.GetAll(p => p.BatchID == vModel.BatchID).FirstOrDefault();
            _repository.Delete(news);
        }

        public void Update(BatchViewModel vModel)
        {
            Batch entity = _repository.GetAll(p => p.BatchID == vModel.BatchID).FirstOrDefault();

            entity.BathCode = vModel.BatchCode;
            entity.CreatedDate = vModel.CreatedDate;
            entity.Description = vModel.Description;
            entity.DistributorID = vModel.DistributorID;
            entity.ParentDistributorID = vModel.ParentDistributorID;
            _repository.Attach(entity);
        }

        public IList<BatchViewModel> GetAll(Expression<Func<BatchViewModel, bool>> whereCondition)
        {
            throw new NotImplementedException();
        }

        public IList<BatchViewModel> GetAll()
        {
            throw new NotImplementedException();
        }

        public IQueryable<BatchViewModel> Query(Expression<Func<BatchViewModel, bool>> whereCondition)
        {
            List<BatchViewModel> newsQuery = new List<BatchViewModel>();
            IQueryable<Batch> query = _repository.GetQueryable();
            AutoMapper.Mapper.CreateMap<Batch, BatchViewModel>()
                .ForMember(dest => dest.BatchID, opt => opt.MapFrom(src => src.BatchID))
                    .ForMember(dest => dest.BatchCode, opt => opt.MapFrom(src => src.BathCode))
                    .ForMember(dest => dest.CreatedDate, opt => opt.MapFrom(src => src.CreatedDate))
                    .ForMember(dest => dest.DistributorID, opt => opt.MapFrom(src => src.DistributorID))
                    .ForMember(dest => dest.ParentDistributorID, opt => opt.MapFrom(src => src.ParentDistributorID))
                    .ForMember(dest => dest.Description, opt => opt.MapFrom(src => src.Description));
            newsQuery = AutoMapper.Mapper.Map(query, newsQuery);
            return newsQuery.AsQueryable().Where(whereCondition);
        }

        public long Count(Expression<Func<BatchViewModel, bool>> whereCondition)
        {
            throw new NotImplementedException();
        }

        public long Count()
        {
            throw new NotImplementedException();
        }
    }
}
